Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / scripts / check-string-escapes.py

Displaying Raw • Download

scripts/check-string-escapes.py renovate/compose-multiplatform (d306fa4c) Text, 3.18 KB

T8b949e#!/usr/bin/env python3
T8b949e"""Guard against Android-style backslash-escaped quotes in Compose resources.

These strings live under ``composeResources`` and are read by the Compose
Multiplatform resources library, whose build-time ``handleSpecialCharacters``
only processes ``\\n``, ``\\t``, ``\\uXXXX`` and ``\\\\`` -- it does NOT strip
``\\"`` or ``\\'`` the way Android's AAPT does. A backslash written before a
quote or apostrophe therefore renders *literally* in the UI (see the Italian
``permission_missing_31`` regression, PR #6357). The correct value is a bare
``"`` / ``'`` (or ``"`` / ``'`` if you want it explicit).

Scope: the English **base** ``values/strings.xml`` only -- the source of truth
authored in this repo. The per-locale ``values-*/`` files are Crowdin mirrors;
their escaping is fixed upstream by the project's custom post-export processor
(strips ``\\'`` and ``\\"`` on export), so editing them here would just be
overwritten on the next sync. This guard catches developer-authored escapes in
the source before they get propagated to every translation.

Exit status is non-zero if any base string contains ``\\"`` or ``\\'``, so it
can gate CI.
"""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations

Tff7b72import T7ee787os
Tff7b72import T7ee787re
Tff7b72import T7ee787sys
Tff7b72from T7ee787pathlib Tff7b72import Te6edf3Path

T8b949e# Repo root = parent of this script's directory (scripts/).
Te6edf3REPO_ROOT Tff7b72= Te6edf3PathTb4b4b4(Tff7b72__file__Tb4b4b4)Tff7b72.Td2a8ffresolveTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffparentTff7b72.Td2a8ffparent

T8b949e# Base (source-language) resource files only: `values/`, never `values-*/`.
Te6edf3BASE_STRINGS_GLOB Tff7b72= Ta5d6ff"Ta5d6ff**/composeResources/values/strings.xmlTa5d6ff"

T8b949e# A backslash directly before a quote or apostrophe, but not one that is itself
T8b949e# escaped (`\\"` = literal backslash + quote, which is intentional). `\n`, `\t`,
T8b949e# `\uXXXX` and `\\` are meaningful CMP escapes and are deliberately left alone.
Te6edf3ESCAPED_QUOTE Tff7b72= Te6edf3reTff7b72.Td2a8ffcompileTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff(?<!Tffea00\\Ta5d6ff)Tffea00\\Ta5d6ff([Ta5d6ff'Tffea00\"Ta5d6ff])Ta5d6ff"Tb4b4b4)

T8b949e# Running inside GitHub Actions enables ::error:: annotations on the PR.
Te6edf3IN_GITHUB_ACTIONS Tff7b72= Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffGITHUB_ACTIONSTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6fftrueTa5d6ff"


Tff7b72def Td2a8ffmainTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3files Tff7b72= Tffa657sortedTb4b4b4(Te6edf3REPO_ROOTTff7b72.Td2a8ffglobTb4b4b4(Te6edf3BASE_STRINGS_GLOBTb4b4b4)Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filesTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6fferror: no base strings.xml found under Tffd700{Te6edf3REPO_ROOTTffd700}Ta5d6ff"Tb4b4b4, Te6edf3fileTff7b72=Te6edf3sysTff7b72.Td2a8ffstderrTb4b4b4)
Tff7b72return T79c0ff2

Te6edf3violationsTb4b4b4: Tffa657listTb4b4b4[Tffa657tupleTb4b4b4[Te6edf3PathTb4b4b4, Tffa657intTb4b4b4, Tffa657strTb4b4b4]Tb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]

Tff7b72for Te6edf3path Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72for Te6edf3linenoTb4b4b4, Te6edf3line Tff7b72in Tffa657enumerateTb4b4b4(Te6edf3pathTff7b72.Td2a8ffread_textTb4b4b4(Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffsplitlinesTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3ESCAPED_QUOTETff7b72.Td2a8ffsearchTb4b4b4(Te6edf3lineTb4b4b4)Tb4b4b4:
Te6edf3violationsTff7b72.Td2a8ffappendTb4b4b4(Tb4b4b4(Te6edf3pathTb4b4b4, Te6edf3linenoTb4b4b4, Te6edf3lineTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4)

Tff7b72if Tff7b72not Te6edf3violationsTb4b4b4:
Tffa657printTb4b4b4(Ta5d6ff"Ta5d6ffNo backslash-escaped quotes found in base string resources.Ta5d6ff"Tb4b4b4)
Tff7b72return T79c0ff0

Tffa657printTb4b4b4(Ta5d6ff"Ta5d6ffBackslash-escaped quotes found in base string resources:Tffea00\nTa5d6ff"Tb4b4b4)
Tff7b72for Te6edf3pathTb4b4b4, Te6edf3linenoTb4b4b4, Te6edf3text Tff7b72in Te6edf3violationsTb4b4b4:
Te6edf3rel Tff7b72= Te6edf3pathTff7b72.Td2a8ffrelative_toTb4b4b4(Te6edf3REPO_ROOTTb4b4b4)
Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffescaped quote/apostrophe renders literally in Compose MultiplatformTa5d6ff"
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff - Tffd700{Te6edf3relTffd700}Ta5d6ff:Tffd700{Te6edf3linenoTffd700}Ta5d6ff: Tffd700{Te6edf3textTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3IN_GITHUB_ACTIONSTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff::error file=Tffd700{Te6edf3relTffd700}Ta5d6ff,line=Tffd700{Te6edf3linenoTffd700}Ta5d6ff::Tffd700{Te6edf3messageTffd700}Ta5d6ff"Tb4b4b4)

Tffa657printTb4b4b4(
Ta5d6ff"Tffea00\nTa5d6ffCompose Multiplatform does not strip Tffea00\\Tffea00\"Ta5d6ff or Tffea00\\Ta5d6ff'Ta5d6ff (unlike Android AAPT), Ta5d6ff"
Ta5d6ff"Ta5d6ffso the backslash shows up in the UI. Use a bare Tffea00\"Ta5d6ff / Ta5d6ff'Ta5d6ff (or &#34; / &#39;).Ta5d6ff"
Tb4b4b4)
Tff7b72return T79c0ff1


Tff7b72if Tff7b72__name__ Tff7b72== Ta5d6ff"Ta5d6ff__main__Ta5d6ff"Tb4b4b4:
Tff7b72raise Tf85149SystemExitTb4b4b4(Te6edf3mainTb4b4b4(Tb4b4b4)Tb4b4b4)

Served by rngit 1.4.2 - Generated in 0.05s